#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<stdbool.h>
#include	<unistd.h>
#include	<time.h>
#include	<netinet/in.h>
#include	<signal.h>
#include	<fcntl.h>
#include	<sys/ioctl.h>
#include	<sys/time.h>
#include	<event.h>
#include	<evutil.h>

#define MAX_PACKET_SIZE		8532
#define COORDINATOR_ID		1
#define MAX_GAP_LENGTH		10
#define STRING_SIZE			1024
#define CONFIG				"/home/parisa/Paxos-UDP/UDP-ring/config/l_config.txt"
#define STRING_SIZE				200000
#define N					5

struct timeval startTime, endTime, end, start, elapsedTime,
		performance_start_time, performance_end_time, throughput_elapsed_time,
		tv;
struct sockaddr_in ipmAddr;
struct event *timeout_ev, *socketEve, *socketEve2;
double throughput_vector[2000];
bool f = false, r_tag = false;
char fn[STRING_SIZE];

int PROCESS_ID, ipm_receiver_sid, senders, deliveryCount = 0, nr = 0, rd = 0,
		redundant = 0;
int lowestDelivered = -1, highestDeliverable = -1, nextDeliver = -1,
		throughput_counter = 0, RECEIVED = 0;
int LOST = 0;
char result_file[STRING_SIZE];
#include "types.h"
inst *data[N];
result results[2000];
lost losts[2000];
int lost_counter = 0;
inst *new_data;
int acceptor_sid;

#include "UDPconnections.h"
#include "TCPconnections.h"
#include "IpSource.h"
#include "learner.h"
#include "performance.h"
#include "initialize.h"

//------------------------------------------------------------------------------
void main_initialize();
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
	//---------------------Variables--------------------------------------------
	char ip[2][STRING_SIZE], port[2][STRING_SIZE], name[STRING_SIZE];
	main_initialize();
	if (argc != 3) {
printf	("Incompatibale call to this function. Try Again.!\n
			1. First Parameter: PROCESS_ID.\n
			2. folder to save the results.\n");
			exit(1);
		}
		PROCESS_ID=atoi(argv[1]);
		IP_PORT(CONFIG,PROCESS_ID,ip,port);
		event_init();

		strcpy(result_file,"/home/parisa/Paxos-UDP/UDP-ring/learner/result/experiment-9/");
		strcat(result_file,argv[2]);
		strcat(result_file,"/");
		strcat(result_file, argv[1]);
		strcat(result_file,".txt");

		strcpy(fn,"/home/parisa/learner-3/throughput/M");
		sprintf(name,"%d",PROCESS_ID);
		strcat(fn, name);
		strcat(fn,".dat");
		//ipmAddr=getAddr(atoi(port[0]), ip[0]);
		losts[lost_counter].count=0;
		//----------------------------------------------------------------------
		tv.tv_sec=1;
		tv.tv_usec=0;
		//=============================Acceptor=====================================

		//close(acceptor_sid);
		//sleep(100);
		//=============================Multicaster==================================
		ipm_receiver_sid=create_ip_multicast_receiver_socket(atoi(port[0]),ip[0]);
		len_addr=sizeof(ipmAddr);
		//==========================================================================


		printf("ip:%s.",ip[1]);
		acceptor_sid = client_connection(atoi(port[1]),ip[1]);

		initialize();
		fprintf("-----------------------------------------------------------\n");
		gettimeofday(&start, NULL);
		gettimeofday(&startTime, NULL);
		gettimeofday(&performance_start_time,NULL);
		//-------Events-------------------------------------------------------------
		event_set(socketEve,ipm_receiver_sid,EV_READ|EV_PERSIST,recv_new_packet,NULL);
		status = event_add(socketEve,NULL);
		assert(status >= 0);
		//==========================================================================
		event_set(socketEve2,acceptor_sid,EV_READ|EV_PERSIST,recv_lost_packet,NULL);
		status = event_add(socketEve2,NULL);
		assert(status >= 0);
		//==========================================================================
		evtimer_set(timeout_ev, compute_performance, timeout_ev);
		status = evtimer_add(timeout_ev,&tv);
		assert(status >= 0);
		//==========================================================================
		event_dispatch();
		exit(0);
	}
	//------------------------------------------------------------------------------
void main_initialize() {
	socketEve = (struct event*) malloc(sizeof(struct event));
	socketEve2 = (struct event*) malloc(sizeof(struct event));
	timeout_ev = (struct event*) malloc(sizeof(struct event));
}
//------------------------------------------------------------------------------
